﻿// See https://aka.ms/new-console-template for more information

using System.Reflection;
using 委托嵌套调用;

InvokeAction invokeAction = new();
//想要在invokeAction.ExeMethod前后添加一些业务逻辑，同时不修改原方法

//Action action1 = new Action(invokeAction.ExeMethod);

//Action<Action> action2 = new Action<Action>(ExecNextMethod);
//action2.Invoke(action1);

//诉求：我希望可以无限制的扩展添加业务逻辑？
//诉求2：在增加一个定义方法，通过委托包装后当作参数传递

//Func<Action, Action> action3 = new Func<Action, Action>(ExecNextMethod2);
//action1 = action3.Invoke(action1);

//Func<Action, Action> action4 = new Func<Action, Action>(ExecNextMethod3);
//action1 = action4.Invoke(action1);

//Func<Action, Action> action5 = new Func<Action, Action>(ExecNextMethod4);
//action1 = action5.Invoke(action1);

//action1.Invoke();

//Type type = typeof(InvokeAction);
//var method = type.GetMethod("ExeMethod");
//var arrtibute1 = method.GetCustomAttribute<ExecNextMethod001Attribute>();

//Action action = new Action(() =>
//{
//    method.Invoke(invokeAction, null);
//});
//action = arrtibute1.Do(action);

//var arrtibute2 = method.GetCustomAttribute<ExecNextMethod002Attribute>();
//action = arrtibute2.Do(action);

//var arrtibute3 = method.GetCustomAttribute<ExecNextMethod003Attribute>();
//action = arrtibute3.Do(action);

//action.Invoke();

//因为类型不一样，所以只能一个个的判断
//如果能一次获取所有特性，放在一个集合中，逐个调用特性的do方法来包装委托，循环执行
//通过定义一个父类，让特性继承父类

Type type = typeof(InvokeAction);
var method = type.GetMethod("ExeMethod");

var attributeList = method.GetCustomAttributes<ExecNextMethodAbstractAttribute>();

Action action = new Action(()=>method.Invoke(invokeAction,null));

foreach (var attribute in attributeList)
{
    action = attribute.Do(action);
}

action.Invoke();

Console.WriteLine("Hello, World!");

void ExecNextMethod(Action action)
{
    Console.WriteLine("beforAction");
    action.Invoke();
    Console.WriteLine("afterAction");
}

Action ExecNextMethod2(Action action)
{
    return new Action(() =>
    {
        Console.WriteLine("beforAction2");
        action.Invoke();
        Console.WriteLine("afterAction2");
    });
}

Action ExecNextMethod3(Action action)
{
    return new Action(() =>
    {
        Console.WriteLine("beforAction3");
        action.Invoke();
        Console.WriteLine("afterAction3");
    });
}

Action ExecNextMethod4(Action action)
{
    return new Action(() =>
    {
        Console.WriteLine("beforAction4");
        action.Invoke();
        Console.WriteLine("afterAction4");
    });
}

public class InvokeAction
{
    [ExecNextMethod004Attribute]
    [ExecNextMethod005Attribute]
    public void ExeMethod()
    {
        Console.WriteLine("Exec Method");
    }
}